
package com.dyx.source.reactor.singleThreadReactor;


import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;

/**
 * 事件处理器，绑定了某类事件，负责执行对应事件的 Task 对事件进行处理
 */
public class Handler implements Runnable {
    final SocketChannel channel;
    final SelectionKey sk;
    ByteBuffer input = ByteBuffer.allocate(1024);
    ByteBuffer output = ByteBuffer.allocate(1024);
    static final int READING = 0, SENDING = 1, CLOSED = 2;
    int state = READING;

    // 缓存每次读取的内容
    StringBuilder request = new StringBuilder();

    Handler(Selector selector, SocketChannel c) throws IOException {
        channel = c;
        //设置成非阻塞
        c.configureBlocking(false);
        // Optionally try first read now
        sk = channel.register(selector, 0);// 注册通道

//        channel.register(selector, SelectionKey.OP_READ);

        //将Handler作为callback对象
        sk.attach(this);

        //第二步,注册Read就绪事件
        sk.interestOps(SelectionKey.OP_READ);
        // 唤醒 select() 方法
        selector.wakeup();
    }

    /**
     * 当读取到 \r\n 时表示结束
     * @param bytes 读取的字节数，-1 通常是连接被关闭，0 非阻塞模式可能返回
     * @throws IOException
     */
    boolean inputIsComplete(int bytes) throws EOFException {
        if (bytes > 0) {
            input.flip(); // 切换成读取模式
            while (input.hasRemaining()) {
                byte ch = input.get();

                if (ch == 3) { // ctrl+c 关闭连接
                    state = CLOSED;
                    return true;
                } else if (ch == '\r') { // continue
                } else if (ch == '\n') {
                    // 读取到了 \r\n 读取结束
                    state = SENDING;
                    return true;
                } else {
                    request.append((char)ch);
                }
            }
        } else if (bytes == -1) {
            // -1 客户端关闭了连接
            throw new EOFException();
        } else {

        } // bytes == 0 继续读取
        return false;
    }


    /**
     * 当用户输入了一个空行，表示连接可以关闭了
     */
    protected boolean outputIsComplete(int written) {
        if (written <= 0) {
            // 用户只敲了个回车， 断开连接
            return true;
        }

        // 清空旧数据，接着处理后续的请求
        output.clear();
        request.delete(0, request.length());
        return false;
    }

    void process() throws EOFException {
        if (state == CLOSED) {
            throw new EOFException();
        } else if (state == SENDING) {
            String requestContent = request.toString(); // 请求内容
            byte[] response = requestContent.getBytes(StandardCharsets.UTF_8);
            output.put(response);
        }

    }

    public void run() {
        try {
            if (state == READING) {
                read(); // 此时通道已经准备好读取字节
            } else if (state == SENDING) {
                send(); // 此时通道已经准备好写入字节
            }
        } catch (IOException ex) { /* ... */ }
    }

    void read() throws IOException {
        input.clear();
        final int read = channel.read(input);
        if (inputIsComplete(read)) { // 如果读取了完整的数据

            process(); // 待发送的数据已经放入发送缓冲区中

            state = SENDING;
            // Normally also do first write now

            // 更改服务的逻辑状态以及要处理的事件类型
            sk.interestOps(SelectionKey.OP_WRITE);
        }
    }



    protected void send() throws IOException {
        int written = -1;
        output.flip();// 切换到读取模式，判断是否有数据要发送
        if (output.hasRemaining()) {
            written = channel.write(output);
        }

        // 检查连接是否处理完毕，是否断开连接
        if (outputIsComplete(written)) {
            sk.channel().close();
        } else {
            // 否则继续读取
            state = READING;
            // 把提示发到界面
            channel.write(ByteBuffer.wrap("\r\nreactor> ".getBytes()));
            sk.interestOps(SelectionKey.OP_READ);
        }

    }
}

